import threading
from decimal import Decimal

from django.db import connection, transaction

from app.decorator import jwt_auth
from app.my_exception import MyException
from app.service import cart, order, member, shop, app_order, payment
from libs import payment_lib, common
from libs.common import success, error
from libs.form import RawJsonForm

'''
无订单退货
1. 获取退货列表
2. 记录退货商品
'''


# @jwt_auth
# def no_order(request, auth):
#     form = RawJsonForm(request.body)
#     bill_num = form.get('bill_num')
#     post_member_id = form.get_int('member_id')
#     post_refund_amount_dec = form.get_dec('refund_amount', None)
#     shop_id = auth.get('shop_id')
#     cashier_id = auth.get('cashier_id')
#     order_dict = {}
#     try:
#         with connection.cursor() as cursor:
#             account = ''
#             if post_member_id > 0:
#                 db_mem = member.get_member_by_id(post_member_id, cursor, ['username'])
#                 account = db_mem.get('username', '')
#
#             db_shop = shop.get_shop_by_id(cursor, shop_id, ['shop_name', 'shop_phone', 'shop_address'])
#             shop_name = db_shop.get('shop_name', '')
#
#             db_cart = cart.query_return_goods_cart(cursor, shop_id, bill_num)
#
#             db_cart_num = len(db_cart)
#             if db_cart_num == 0:
#                 return error('退货商品不存在')
#             cart_cat_dict, cart_total_amount = cart.pick_cart_goods(db_cart)
#             remark = form.get('remark')
#
#             refund_amount_dec = cart_total_amount
#             if post_refund_amount_dec is not None:
#                 refund_amount_dec = post_refund_amount_dec
#
#             with transaction.atomic():
#                 for cart_cat in cart_cat_dict:
#                     if cart_cat == 1:
#                         remark = '退换货单据'
#                         app_order_state = 11
#                         if refund_amount_dec > 0:
#                             total_price = 0
#                         else:
#                             total_price = refund_amount_dec
#                     elif cart_cat == 2:
#                         app_order_state = 12
#                         if refund_amount_dec > 0:
#                             total_price = refund_amount_dec
#                         else:
#                             total_price = 0
#                     else:
#                         return error('无效的订单类型')
#                     order_sn = order.gen_order_sn(cart_cat)
#                     order_base_data = {
#                         'shop_id': shop_id,
#                         'cashier_id': cashier_id,
#                         'order_sn': order_sn,
#                         'bill_num': bill_num,
#                         'pay_method': '现金',
#                         'member_id': post_member_id,
#                         'account': account,
#                         'status': -1,
#                         'remark': remark,
#                         'cart_typ': cart_cat,
#                         'total_price': total_price
#                     }
#                     cart_goods_group = cart_cat_dict.get(cart_cat)
#                     app_order_base_data = {
#                         'member_id': account,
#                         'shoper_name': shop_name,
#                         'state': app_order_state,
#                     }
#                     order_data, order_detail_arr, err = order.save_cart_to_order(cashier_id, app_order_base_data, cart_goods_group, order_base_data, cursor)
#                     if err is not None:
#                         raise MyException(err)
#                     order_dict.update({
#                         cart_cat: {
#                             'order': order_data,
#                             'order_detail': order_detail_arr,
#                         }
#                     })
#
#                 affected, err = cart.update_cart_status_by_bill_num(cursor, shop_id, bill_num)
#                 if affected == 0 or err is not None:
#                     raise MyException('更新退货状态失败')
#     except MyException as e:
#         return error(str(e))
#     except Exception as e:
#         err = '创建退货单异常'
#         print(err, e)
#         return error(err)
#     return success(order_data=order_dict, shop=db_shop, refund_amount=refund_amount_dec)


@jwt_auth
def no_order_v2(request, auth):
    form = RawJsonForm(request.body)
    bill_num = form.get('bill_num')
    post_member_id = form.get_int('member_id')
    post_refund_amount_dec = form.get_dec('refund_amount', None)
    shop_id = auth.get('shop_id')
    cashier_id = auth.get('cashier_id')
    try:
        with connection.cursor() as cursor:
            account = ''
            if post_member_id > 0:
                db_mem = member.get_member_by_id(post_member_id, cursor, ['username'])
                account = db_mem.get('username', '')
            coupon_status = 0
            if account != '':
                coupon_status = 1
            db_shop = shop.get_shop_by_id(cursor, shop_id, ['shop_name', 'shop_phone', 'shop_address'])
            shop_name = db_shop.get('shop_name', '')
            db_cart = cart.query_return_goods_cart(cursor, shop_id, bill_num)
            db_cart_num = len(db_cart)
            if db_cart_num == 0:
                return error('退货商品不存在')
            cart_total_amount, cart_typ_set, order_goods_num = cart.get_cart_total_amount(db_cart)
            remark = form.get('remark')
            cart_typ_mixed = 0
            for ct_item in cart_typ_set:
                if type(ct_item) is int:
                    cart_typ_mixed += ct_item
            refund_amount_dec = cart_total_amount
            if post_refund_amount_dec is not None:
                refund_amount_dec = post_refund_amount_dec
            amount_sign = 1
            if refund_amount_dec < 0:
                amount_sign = -1
            refund_amount_pos = abs(refund_amount_dec)
            with transaction.atomic():
                order_sn = order.gen_order_sn(1)
                order_base_data = {
                    'shop_id': shop_id,
                    'cashier_id': cashier_id,
                    'order_sn': order_sn,
                    'bill_num': bill_num,
                    'pay_method': '现金',
                    'member_id': post_member_id,
                    'account': account,
                    'total_price': refund_amount_pos,
                    'cart_typ': cart_typ_mixed,
                    'coupon_status': coupon_status,
                    'status': -5,
                    'remark': remark,
                    'amount_sign': amount_sign,
                }
                app_order_base_data = {
                    'member_id': account,
                    'shoper_name': shop_name,
                    'state': 11,
                }
                cart_goods_group = {
                    'arr': db_cart,
                    'cart_total_price': refund_amount_pos,
                    'num': order_goods_num,
                }
                order_data, order_detail_arr, err = order.save_cart_to_order_v2(cashier_id,
                                                                                app_order_base_data,
                                                                                cart_goods_group,
                                                                                order_base_data,
                                                                                cursor)
                if err is not None:
                    raise MyException(err)
                affected, err = cart.update_cart_status_by_bill_num(cursor, shop_id, bill_num)
                if affected == 0 or err is not None:
                    raise MyException('更新退货状态失败')
    except MyException as e:
        return error(str(e))
    except Exception as e:
        err = '创建退货单异常'
        print(err, e)
        return error(err)

    if account != '':
        cs_order_id = order_data.get('id')
        th = threading.Thread(target=order.update_coupon_status, args=(cashier_id, account, cs_order_id,))
        th.start()

    return success(order_data=order_data, order_detail=order_detail_arr, shop=db_shop, refund_amount=refund_amount_dec)


@jwt_auth
def no_order_v3(request, auth):
    form = RawJsonForm(request.body)
    bill_num = form.get('bill_num')
    post_member_id = form.get_int('member_id')
    post_refund_amount_dec = form.get_dec('refund_amount', None)
    shop_id = auth.get('shop_id')
    cashier_id = auth.get('cashier_id')
    pay_code = form.get('pay_code', default=None)
    order_status = -5  # 默认订单状态为无订单退换货，如有第三方支付，状态为未结
    try:
        third_party_pay_flag = 0  # 支付类型ID
        third_party_pay_data = {}  # 第三方支付
        valid_mem_id = 0
        with connection.cursor() as cursor:
            account = ''
            if post_member_id > 0:
                db_mem = member.get_member_with_cursor(cursor, post_member_id)
                db_mem_id = db_mem.get('id', 0)
                account = db_mem.get('username', '')
                if db_mem_id == 0:
                    raise MyException('会员信息不存在')
                valid_mem_id = db_mem_id
            coupon_status = 0
            if account != '':
                coupon_status = 1
            db_shop = shop.get_shop_by_id(cursor, shop_id, ['shop_name', 'shop_phone', 'shop_address'])
            shop_name = db_shop.get('shop_name', '')
            db_cart = cart.query_return_goods_cart(cursor, shop_id, bill_num)
            db_cart_num = len(db_cart)
            if db_cart_num == 0:
                return error('退货商品不存在')
            cart_total_amount, cart_typ_set, order_goods_num = cart.get_cart_total_amount(db_cart)

            cart_total_amount_abs = abs(cart_total_amount)
            # 用户实际退款金额参数不存在，使用退款购物车总额作为实际退款金额
            if post_refund_amount_dec is None:
                post_refund_amount_dec = cart_total_amount
            elif post_refund_amount_dec != cart_total_amount:
                return error('支付总金额与退换货总额不符')

            order_sn = order.gen_order_sn(1)
            pay_method_counter = 0
            is_mixed_pay = 0
            member_fund_update_counter = 0
            app_pay_mode = 0
            app_pay_mode_map = app_order.APP_PAY_MODE_MAP
            now = common.get_ts()
            if cart_total_amount > 0:
                pay_methods = form.get_list('pay_methods')
                post_pay_total_dec, pay_method_label, selected_pay_method_dic, err = payment.check_post_payments(
                    pay_methods)
                if err is not None:
                    return error(err)

                if cart_total_amount != post_pay_total_dec:
                    return error('支付明细与支付总金额不符')
                # 需要用户支付
                if 2 in selected_pay_method_dic and selected_pay_method_dic[2].get('pay_amount') > 0:
                    if post_member_id <= 0:
                        return error('支付方式中包含“仓储卡”，需要提供会员信息')
                if 3 in selected_pay_method_dic and selected_pay_method_dic[3].get(
                        'pay_amount') > 0 and post_member_id <= 0:
                    return error('支付方式中包含“余额”，需要提供会员信息')
                if 100 in selected_pay_method_dic:
                    if pay_code is None:
                        if selected_pay_method_dic[100].get('pay_amount') > 0:
                            return error('支付方式中包含“微信/支付宝”，需要提供付款码')
                    else:
                        pay_code_info = payment_lib.get_pay_code_type(pay_code)
                        if pay_code_info is None:
                            return error('无效的第三方支付方式')
                        elif type(pay_code_info) is dict:
                            third_party_pay_flag = pay_code_info.get('code')
                    selected_pay_method_dic[100].update({'third_party_pay_flag': third_party_pay_flag})
            else:
                # 购物车金额小于0，使用现金退款给顾客
                app_pay_mode = 4
                pay_method_label = '现金'
                selected_pay_method_dic = {1: {
                    'pay_amount': cart_total_amount,
                    'confirmed': now
                }}

            remark = form.get('remark')
            cart_typ_mixed = 0
            for ct_item in cart_typ_set:
                if type(ct_item) is int:
                    cart_typ_mixed += ct_item
            refund_amount_dec = cart_total_amount
            if post_refund_amount_dec is not None:
                refund_amount_dec = post_refund_amount_dec
            amount_sign = 1
            if refund_amount_dec < 0:
                amount_sign = -1
            refund_amount_pos = abs(refund_amount_dec)

            payAmountAllocFlag = False  # 支付金额分配完成标记
            total_amount_counter_dec = Decimal('0')
            with transaction.atomic():
                # 购物车金额大于0，用户需要支付
                if cart_total_amount > 0:
                    for pay_method_typ in selected_pay_method_dic:
                        pay_method_counter += 1
                        payAmountDec = selected_pay_method_dic[pay_method_typ].get('pay_amount')
                        if payAmountDec > 0:
                            nextCounterDec = total_amount_counter_dec + payAmountDec
                            if payAmountAllocFlag:
                                del (selected_pay_method_dic[pay_method_typ])
                                break

                            # 如果提交的支付总额超过商品总额，标记支付分配完成
                            if nextCounterDec >= cart_total_amount_abs:
                                payAmountAllocFlag = True
                                payAmountDec = post_refund_amount_dec - total_amount_counter_dec
                                selected_pay_method_dic[pay_method_typ].update({'pay_amount': payAmountDec})

                            if pay_method_typ == 1:  # 现金
                                app_pay_mode = 4
                                selected_pay_method_dic[pay_method_typ].update({'confirmed': now})
                            elif pay_method_typ == 2:  # 仓储卡
                                app_pay_mode = 5
                                selected_pay_method_dic[pay_method_typ].update({'confirmed': now})
                                if valid_mem_id == 0:
                                    raise MyException('使用仓储卡支付，请提供有效会员信息')
                                if member_fund_update_counter > 0:
                                    db_mem.update({'ver': db_mem.get('ver') + member_fund_update_counter})
                                # 处理仓储卡支付
                                proc_err = order.process_member_storage_fund(cursor, db_mem, payAmountDec, 'reduce')
                                if proc_err is not None:
                                    raise MyException(proc_err)
                                member_fund_update_counter += 1
                            elif pay_method_typ == 3:  # 余额
                                app_pay_mode = 1
                                selected_pay_method_dic[pay_method_typ].update({'confirmed': now})
                                if valid_mem_id == 0:
                                    raise MyException('使用会员余额支付，请提供有效会员信息')
                                if member_fund_update_counter > 0:
                                    db_mem.update({'ver': db_mem.get('ver') + member_fund_update_counter})
                                # 处理余额支付
                                proc_err = order.process_member_balance_fund(cursor, db_mem, payAmountDec, 'reduce')
                                if proc_err is not None:
                                    raise MyException(proc_err)
                                member_fund_update_counter += 1
                            elif pay_method_typ == 10:  # 线下扫码
                                app_pay_mode = 7
                                selected_pay_method_dic[pay_method_typ].update({'confirmed': now})
                                # 处理线下扫码支付
                                proc_err = order.process_scan_payment()
                                if proc_err is not None:
                                    raise MyException(proc_err)
                            elif pay_method_typ == 100:  # 微信/支付宝
                                if third_party_pay_flag == 1:
                                    app_pay_mode = 2
                                elif third_party_pay_flag == 2:
                                    app_pay_mode = 3

                                pay_fen = int(payAmountDec * Decimal('100'))
                                third_party_pay_data.update({'pay_fen': pay_fen, 'order_sn': order_sn})
                                selected_pay_method_dic[pay_method_typ].update({'confirmed': 0})
                                # 处理微信/支付宝支付
                                proc_err = order.process_wx_or_ali_payment()
                                if proc_err is not None:
                                    raise MyException(proc_err)
                                order_status = 0
                            else:
                                raise MyException('无效的支付方式')
                    if pay_method_counter > 1:
                        is_mixed_pay = 1
                        app_pay_mode = 99

                only_pay_no = app_pay_mode_map.get(app_pay_mode, '')
                order_base_data = {
                    'shop_id': shop_id,
                    'cashier_id': cashier_id,
                    'order_sn': order_sn,
                    'bill_num': bill_num,
                    'pay_method': pay_method_label,
                    'member_id': post_member_id,
                    'account': account,
                    'total_price': refund_amount_pos,
                    'cart_typ': cart_typ_mixed,
                    'coupon_status': coupon_status,
                    'status': order_status,
                    'remark': remark,
                    'amount_sign': amount_sign,
                }

                app_order_state = 11
                if order_status == 0:
                    app_order_state = 0

                app_order_base_data = {
                    'member_id': account,
                    'shoper_name': shop_name,
                    'state': app_order_state,
                    'is_mixed_pay': is_mixed_pay,
                    'pay_mode': app_pay_mode,
                    'only_pay_no': only_pay_no,
                }
                cart_goods_group = {
                    'arr': db_cart,
                    'cart_total_price': cart_total_amount,
                    'num': order_goods_num,
                }
                order_data, order_detail_arr, err = order.save_cart_to_order_v3(cashier_id,
                                                                                app_order_base_data,
                                                                                cart_goods_group,
                                                                                order_base_data,
                                                                                cursor)
                if err is not None:
                    raise MyException(err)
                cs_order_id = order_data.get('id')

                # 记录订单支付日志
                pay_log_dict, err = order.save_order_pay_logs(cashier_id, cs_order_id, selected_pay_method_dic, cursor)
                if err is not None:
                    raise MyException(err)

                affected, err = cart.update_cart_status_by_bill_num(cursor, shop_id, bill_num)
                if affected == 0 or err is not None:
                    raise MyException('更新退货状态失败')

    except MyException as e:
        return error(str(e))
    except Exception as e:
        err = '创建退货单异常'
        print(err, e)
        return error(err)

    # todo 第三方支付
    if pay_code is not None:
        # 处理第三方支付，第三方支付库存已扣，如确认支付失败，需要恢复库存
        if 100 in pay_log_dict:
            pay_log_id = pay_log_dict[100]
            th = threading.Thread(target=payment.process_cart_payment, args=(cashier_id,
                                                                             cs_order_id,
                                                                             order_sn,
                                                                             pay_log_id,
                                                                             third_party_pay_flag,
                                                                             pay_code,
                                                                             third_party_pay_data,))
            th.start()
    if account != '':
        cs_order_id = order_data.get('id')
        th = threading.Thread(target=order.update_coupon_status, args=(cashier_id, account, cs_order_id,))
        th.start()

    return success(order_data=order_data, order_detail=order_detail_arr, shop=db_shop, refund_amount=refund_amount_dec)
